home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / mail / mailhand / email-pa.000 / email-pa / email-pager / chat-source / chat.c < prev    next >
C/C++ Source or Header  |  1994-10-11  |  19KB  |  1,167 lines

  1. /*
  2.  *    Chat -- a program for automatic session establishment (i.e. dial
  3.  *        the phone and log in).
  4.  *
  5.  *    This software is in the public domain.
  6.  *
  7.  *    Please send all bug reports, requests for information, etc. to:
  8.  *
  9.  *        Al Longyear (longyear@netcom.com)
  10.  *        (I was the last person to change this code.)
  11.  *
  12.  *    The original author is:
  13.  *
  14.  *        Karl Fox <karl@MorningStar.Com>
  15.  *        Morning Star Technologies, Inc.
  16.  *        1760 Zollinger Road
  17.  *        Columbus, OH  43221
  18.  *        (614)451-1883
  19.  */
  20.  
  21. static char rcsid[] = "$Id: chat.c,v 1.4 1994/05/30 00:30:37 paulus Exp $";
  22.  
  23. #include <stdio.h>
  24. #include <fcntl.h>
  25. #include <signal.h>
  26. #include <errno.h>
  27. #include <string.h>
  28. #include <stdlib.h>
  29. #include <sys/types.h>
  30. #include <sys/stat.h>
  31. #include <syslog.h>
  32.  
  33. #ifndef TERMIO
  34. #undef    TERMIOS
  35. #define TERMIOS
  36. #endif
  37.  
  38. #ifdef sun
  39. # if defined(SUNOS) && SUNOS >= 41
  40. # ifndef HDB
  41. #  define    HDB
  42. # endif
  43. # endif
  44. #endif
  45.  
  46. #ifdef TERMIO
  47. #include <termio.h>
  48. #endif
  49. #ifdef TERMIOS
  50. #include <termios.h>
  51. #endif
  52.  
  53. #define    STR_LEN    1024
  54.  
  55. #ifndef SIGTYPE
  56. #define SIGTYPE void
  57. #endif
  58.  
  59. #ifdef __STDC__
  60. #undef __P
  61. #define __P(x)    x
  62. #else
  63. #define __P(x)    ()
  64. #define const
  65. #endif
  66.  
  67. /*************** Micro getopt() *********************************************/
  68. #define    OPTION(c,v)    (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
  69.                 (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
  70.                 &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
  71. #define    OPTARG(c,v)    (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
  72.                 (_O=4,(char*)0):(char*)0)
  73. #define    OPTONLYARG(c,v)    (_O&2&&**v?(_O=1,--c,*v++):(char*)0)
  74. #define    ARG(c,v)    (c?(--c,*v++):(char*)0)
  75.  
  76. static int _O = 0;        /* Internal state */
  77. /*************** Micro getopt() *********************************************/
  78.  
  79. char *program_name;
  80.  
  81. #ifndef LOCK_DIR
  82. # ifdef __NetBSD__
  83. # define    PIDSTRING
  84. # define    LOCK_DIR    "/var/spool/lock"
  85. # else
  86. #  ifdef HDB
  87. #   define    PIDSTRING
  88. #   define    LOCK_DIR    "/usr/spool/locks"
  89. #  else /* HDB */
  90. #   define    LOCK_DIR    "/usr/spool/uucp"
  91. #  endif /* HDB */
  92. # endif
  93. #endif /* LOCK_DIR */
  94.  
  95. #define    MAX_ABORTS        50
  96. #define    DEFAULT_CHAT_TIMEOUT    45
  97.  
  98. int verbose = 0;
  99. int quiet = 0;
  100. char *lock_file = (char *)0;
  101. char *chat_file = (char *)0;
  102. int timeout = DEFAULT_CHAT_TIMEOUT;
  103.  
  104. int have_tty_parameters = 0;
  105. #ifdef TERMIO
  106. struct termio saved_tty_parameters;
  107. #endif
  108. #ifdef TERMIOS
  109. struct termios saved_tty_parameters;
  110. #endif
  111.  
  112. char *abort_string[MAX_ABORTS], *fail_reason = (char *)0,
  113.     fail_buffer[50];
  114. int n_aborts = 0, abort_next = 0, timeout_next = 0;
  115.  
  116. void *dup_mem __P((void *b, size_t c));
  117. void *copy_of __P((char *s));
  118. void usage __P((void));
  119. void logf __P((const char *str));
  120. void logflush __P((void));
  121. void fatal __P((const char *msg));
  122. void sysfatal __P((const char *msg));
  123. SIGTYPE sigalrm __P((int signo));
  124. SIGTYPE sigint __P((int signo));
  125. SIGTYPE sigterm __P((int signo));
  126. SIGTYPE sighup __P((int signo));
  127. void unalarm __P((void));
  128. void init __P((void));
  129. void set_tty_parameters __P((void));
  130. void break_sequence __P((void));
  131. void terminate __P((int status));
  132. void do_file __P((char *chat_file));
  133. void lock __P((void));
  134. void delay __P((void));
  135. int  get_string __P((register char *string));
  136. int  put_string __P((register char *s));
  137. int  write_char __P((int c));
  138. int  put_char __P((char c));
  139. int  get_char __P((void));
  140. void chat_send __P((register char *s));
  141. char *character __P((char c));
  142. void chat_expect __P((register char *s));
  143. char *clean __P((register char *s, int sending));
  144. void unlock __P((void));
  145. void lock __P((void));
  146. void break_sequence __P((void));
  147. void terminate __P((int status));
  148. void die __P((void));
  149.  
  150. void *dup_mem(b, c)
  151. void *b;
  152. size_t c;
  153.     {
  154.     void *ans = malloc (c);
  155.     if (!ans)
  156.     fatal ("memory error!\n");
  157.     memcpy (ans, b, c);
  158.     return ans;
  159.     }
  160.  
  161. void *copy_of (s)
  162. char *s;
  163.     {
  164.     return dup_mem (s, strlen (s) + 1);
  165.     }
  166.  
  167. /*
  168.  *    chat [ -v ] [ -t timeout ] [ -l lock-file ] [ -f chat-file ] \
  169.  *        [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]]
  170.  *
  171.  *    Perform a UUCP-dialer-like chat script on stdin and stdout.
  172.  */
  173. int
  174. main(argc, argv)
  175. int argc;
  176. char **argv;
  177.     {
  178.     int option;
  179.     char *arg;
  180.  
  181.     program_name = *argv;
  182.  
  183.     while (option = OPTION(argc, argv))
  184.     switch (option)
  185.         {
  186.         case 'v':
  187.         ++verbose;
  188.         break;
  189.  
  190.         case 'f':
  191.         if (arg = OPTARG(argc, argv))
  192.             chat_file = copy_of(arg);
  193.         else
  194.             usage();
  195.  
  196.         break;
  197.  
  198.         case 'l':
  199.         if (arg = OPTARG(argc, argv))
  200.             lock_file = copy_of(arg);
  201.         else
  202.             usage();
  203.  
  204.         break;
  205.  
  206.         case 't':
  207.         if (arg = OPTARG(argc, argv))
  208.             timeout = atoi(arg);
  209.         else
  210.             usage();
  211.  
  212.         break;
  213.  
  214.         default:
  215.         usage();
  216.         }
  217.  
  218. #ifdef ultrix
  219.     openlog("chat", LOG_PID);
  220. #else
  221.     openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2);
  222.  
  223.     if (verbose) {
  224.     setlogmask(LOG_UPTO(LOG_INFO));
  225.     } else {
  226.     setlogmask(LOG_UPTO(LOG_WARNING));
  227.     }
  228. #endif
  229.  
  230.     init();
  231.     
  232.     if (chat_file != NULL)
  233.     {
  234.     arg = ARG(argc, argv);
  235.     if (arg != NULL)
  236.         usage();
  237.     else
  238.         do_file (chat_file);
  239.     }
  240.     else
  241.     {
  242.     while (arg = ARG(argc, argv))
  243.         {
  244.         chat_expect(arg);
  245.  
  246.         if (arg = ARG(argc, argv))
  247.         chat_send(arg);
  248.         }
  249.     }
  250.  
  251.     terminate(0);
  252.     }
  253.  
  254. /*
  255.  *  Process a chat script when read from a file.
  256.  */
  257.  
  258. void do_file (chat_file)
  259. char *chat_file;
  260.     {
  261.     int linect, len, sendflg;
  262.     char *sp, *arg, quote;
  263.     char buf [STR_LEN];
  264.     FILE *cfp;
  265.  
  266.     if ((cfp = fopen (chat_file, "r")) == NULL)
  267.     {
  268.     syslog (LOG_ERR, "%s -- open failed: %m", chat_file);
  269.     terminate (1);
  270.     }
  271.  
  272.     linect = 0;
  273.     sendflg = 0;
  274.  
  275.     while (fgets(buf, STR_LEN, cfp) != NULL)
  276.     {
  277.     sp = strchr (buf, '\n');
  278.     if (sp)
  279.         *sp = '\0';
  280.  
  281.     linect++;
  282.     sp = buf;
  283.     while (*sp != '\0')
  284.         {
  285.         if (*sp == ' ' || *sp == '\t')
  286.         {
  287.         ++sp;
  288.         continue;
  289.         }
  290.  
  291.         if (*sp == '"' || *sp == '\'')
  292.         {
  293.         quote = *sp++;
  294.         arg = sp;
  295.         while (*sp != quote)
  296.             {
  297.             if (*sp == '\0')
  298.             {
  299.             syslog (LOG_ERR, "unterminated quote (line %d)",
  300.                 linect);
  301.             terminate (1);
  302.             }
  303.             
  304.             if (*sp++ == '\\')
  305.             if (*sp != '\0')
  306.                 ++sp;
  307.             }
  308.         }
  309.         else
  310.         {
  311.         arg = sp;
  312.         while (*sp != '\0' && *sp != ' ' && *sp != '\t')
  313.             ++sp;
  314.         }
  315.  
  316.         if (*sp != '\0')
  317.         *sp++ = '\0';
  318.  
  319.         if (sendflg)
  320.         {
  321.         chat_send (arg);
  322.         }
  323.         else
  324.         {
  325.         chat_expect (arg);
  326.         }
  327.         sendflg = !sendflg;
  328.         }
  329.     }
  330.     fclose (cfp);
  331.     }
  332.  
  333. /*
  334.  *    We got an error parsing the command line.
  335.  */
  336. void usage()
  337.     {
  338.     fprintf(stderr, "\
  339. Usage: %s [-v] [-l lock-file] [-t timeout] {-f chat-file || chat-script}\n",
  340.         program_name);
  341.     exit(1);
  342.     }
  343.  
  344. char line[256];
  345. char *p;
  346.  
  347. void logf (str)
  348. const char *str;
  349.     {
  350.     p = line + strlen(line);
  351.     strcat (p, str);
  352.  
  353.     if (str[strlen(str)-1] == '\n')
  354.     {
  355.     syslog (LOG_INFO, "%s", line);
  356.     line[0] = 0;
  357.     }
  358.     }
  359.  
  360. void logflush()
  361.     {
  362.     if (line[0] != 0)
  363.     {
  364.     syslog(LOG_INFO, "%s", line);
  365.     line[0] = 0;
  366.         }
  367.     }
  368.  
  369. /*
  370.  *    Unlock and terminate with an error.
  371.  */
  372. void die()
  373.     {
  374.     unlock();
  375.     terminate(1);
  376.     }
  377.  
  378. /*
  379.  *    Print an error message and terminate.
  380.  */
  381.  
  382. void fatal (msg)
  383. const char *msg;
  384.     {
  385.     syslog(LOG_ERR, "%s", msg);
  386.     unlock();
  387.     terminate(1);
  388.     }
  389.  
  390. /*
  391.  *    Print an error message along with the system error message and
  392.  *    terminate.
  393.  */
  394.  
  395. void sysfatal (msg)
  396. const char *msg;
  397.     {
  398.     syslog(LOG_ERR, "%s: %m", msg);
  399.     unlock();
  400.     terminate(1);
  401.     }
  402.  
  403. int alarmed = 0;
  404.  
  405. SIGTYPE sigalrm(signo)
  406. int signo;
  407.     {
  408.     int flags;
  409.  
  410.     alarm(1);
  411.     alarmed = 1;        /* Reset alarm to avoid race window */
  412.     signal(SIGALRM, sigalrm);    /* that can cause hanging in read() */
  413.  
  414.     logflush();
  415.     if ((flags = fcntl(0, F_GETFL, 0)) == -1)
  416.     sysfatal("Can't get file mode flags on stdin");
  417.     else
  418.     if (fcntl(0, F_SETFL, flags | FNDELAY) == -1)
  419.         sysfatal("Can't set file mode flags on stdin");
  420.  
  421.     if (verbose)
  422.     {
  423.     syslog(LOG_INFO, "alarm");
  424.     }
  425.     }
  426.  
  427. void unalarm()
  428.     {
  429.     int flags;
  430.  
  431.     if ((flags = fcntl(0, F_GETFL, 0)) == -1)
  432.     sysfatal("Can't get file mode flags on stdin");
  433.     else
  434.     if (fcntl(0, F_SETFL, flags & ~FNDELAY) == -1)
  435.         sysfatal("Can't set file mode flags on stdin");
  436.     }
  437.  
  438. SIGTYPE sigint(signo)
  439. int signo;
  440.     {
  441.     fatal("SIGINT");
  442.     }
  443.  
  444. SIGTYPE sigterm(signo)
  445. int signo;
  446.     {
  447.     fatal("SIGTERM");
  448.     }
  449.  
  450. SIGTYPE sighup(signo)
  451. int signo;
  452.     {
  453.     fatal("SIGHUP");
  454.     }
  455.  
  456. void init()
  457.     {
  458.     signal(SIGINT, sigint);
  459.     signal(SIGTERM, sigterm);
  460.     signal(SIGHUP, sighup);
  461.  
  462.     if (lock_file)
  463.     lock();
  464.  
  465.     set_tty_parameters();
  466.     signal(SIGALRM, sigalrm);
  467.     alarm(0);
  468.     alarmed = 0;
  469.     }
  470.  
  471. void set_tty_parameters()
  472.     {
  473. #ifdef TERMIO
  474.     struct termio t;
  475.  
  476.     if (ioctl(0, TCGETA, &t) < 0)
  477.     sysfatal("Can't get terminal parameters");
  478. #endif
  479. #ifdef TERMIOS
  480.     struct termios t;
  481.  
  482.     if (tcgetattr(0, &t) < 0)
  483.     sysfatal("Can't get terminal parameters");
  484. #endif
  485.  
  486.     saved_tty_parameters = t;
  487.     have_tty_parameters = 1;
  488.  
  489.     t.c_iflag |= IGNBRK | ISTRIP | IGNPAR;
  490.     t.c_oflag  = 0;
  491.     t.c_lflag  = 0;
  492.     t.c_cc[VERASE] = t.c_cc[VKILL] = 0;
  493.     t.c_cc[VMIN] = 1;
  494.     t.c_cc[VTIME] = 0;
  495.  
  496. #ifdef TERMIO
  497.     if (ioctl(0, TCSETA, &t) < 0)
  498.     sysfatal("Can't set terminal parameters");
  499. #endif
  500. #ifdef TERMIOS
  501.     if (tcsetattr(0, TCSANOW, &t) < 0)
  502.     sysfatal("Can't set terminal parameters");
  503. #endif
  504.     }
  505.  
  506. void break_sequence()
  507.     {
  508. #ifdef TERMIOS
  509.     tcsendbreak (0, 0);
  510. #endif
  511.     }
  512.  
  513. void terminate(status)
  514. int status;
  515.     {
  516.     if (have_tty_parameters &&
  517. #ifdef TERMIO
  518.         ioctl(0, TCSETA, &saved_tty_parameters) < 0
  519. #endif
  520. #ifdef TERMIOS
  521.     tcsetattr(0, TCSANOW, &saved_tty_parameters) < 0
  522. #endif
  523.     ) {
  524.     syslog(LOG_ERR, "Can't restore terminal parameters: %m");
  525.     unlock();
  526.     exit(1);
  527.         }
  528.     exit(status);
  529.     }
  530.  
  531. /*
  532.  *    Create a lock file for the named lock device
  533.  */
  534. void lock()
  535.     {
  536.     int fd, pid;
  537. # ifdef PIDSTRING
  538.     char hdb_lock_buffer[12];
  539. # endif
  540.  
  541.     lock_file = strcat(strcat(strcpy(malloc(strlen(LOCK_DIR)
  542.                        + 1 + strlen(lock_file) + 1),
  543.                 LOCK_DIR), "/"), lock_file);
  544.  
  545.     if ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0)
  546.     {
  547.     char *s = lock_file;
  548.     lock_file = (char *)0;    /* Don't remove someone else's lock file! */
  549.     syslog(LOG_ERR, "Can't get lock file '%s': %m", s);
  550.     die();
  551.     }
  552.  
  553. # ifdef PIDSTRING
  554.     sprintf(hdb_lock_buffer, "%10d\n", getppid());
  555.     write(fd, hdb_lock_buffer, 11);
  556. # else
  557.     pid = getppid();
  558.     write(fd, &pid, sizeof pid);
  559. # endif
  560.  
  561.     close(fd);
  562.     }
  563.  
  564. /*
  565.  *    Remove our lockfile
  566.  */
  567. void unlock()
  568.     {
  569.     if (lock_file)
  570.     {
  571.     unlink(lock_file);
  572.     lock_file = (char *)0;
  573.     }
  574.     }
  575.  
  576. /*
  577.  *    'Clean up' this string.
  578.  */
  579. char *clean(s, sending)
  580. register char *s;
  581. int sending;
  582.     {
  583.     char temp[STR_LEN], cur_chr;
  584.     register char *s1;
  585.     int add_return = sending;
  586. #define isoctal(chr) (((chr) >= '0') && ((chr) <= '7'))
  587.  
  588.     s1 = temp;
  589.     while (*s)
  590.     {
  591.     cur_chr = *s++;
  592.     if (cur_chr == '^')
  593.         {
  594.         cur_chr = *s++;
  595.         if (cur_chr == '\0')
  596.         {
  597.         *s1++ = '^';
  598.         break;
  599.         }
  600.         cur_chr &= 0x1F;
  601.         if (cur_chr != 0)
  602.         *s1++ = cur_chr;
  603.         continue;
  604.         }
  605.  
  606.     if (cur_chr != '\\')
  607.         {
  608.         *s1++ = cur_chr;
  609.         continue;
  610.         }
  611.  
  612.     cur_chr = *s++;
  613.     if (cur_chr == '\0')
  614.         {
  615.         if (sending)
  616.         {
  617.         *s1++ = '\\';
  618.         *s1++ = '\\';
  619.         }
  620.         break;
  621.         }
  622.  
  623.     switch (cur_chr)
  624.         {
  625.     case 'b':
  626.         *s1++ = '\b';
  627.         break;
  628.  
  629.     case 'c':
  630.         if (sending && *s == '\0')
  631.         add_return = 0;
  632.         else
  633.         *s1++ = cur_chr;
  634.         break;
  635.  
  636.     case '\\':
  637.     case 'K':
  638.     case 'p':
  639.     case 'd':
  640.         if (sending)
  641.         *s1++ = '\\';
  642.  
  643.         *s1++ = cur_chr;
  644.         break;
  645.  
  646.     case 'q':
  647.         quiet = ! quiet;
  648.         break;
  649.  
  650.     case 'r':
  651.         *s1++ = '\r';
  652.         break;
  653.  
  654.     case 'n':
  655.         *s1++ = '\n';
  656.         break;
  657.  
  658.     case 's':
  659.         *s1++ = ' ';
  660.         break;
  661.  
  662.     case 't':
  663.         *s1++ = '\t';
  664.         break;
  665.  
  666.     case 'N':
  667.         if (sending)
  668.         {
  669.         *s1++ = '\\';
  670.         *s1++ = '\0';
  671.         }
  672.         else
  673.         *s1++ = 'N';
  674.         break;
  675.         
  676.     default:
  677.         if (isoctal (cur_chr))
  678.         {
  679.         cur_chr &= 0x07;
  680.         if (isoctal (*s))
  681.             {
  682.             cur_chr <<= 3;
  683.             cur_chr |= *s++ - '0';
  684.             if (isoctal (*s))
  685.             {
  686.             cur_chr <<= 3;
  687.             cur_chr |= *s++ - '0';
  688.             }
  689.             }
  690.  
  691.         if (cur_chr != 0 || sending)
  692.             {
  693.             if (sending && (cur_chr == '\\' || cur_chr == 0))
  694.             *s1++ = '\\';
  695.             *s1++ = cur_chr;
  696.             }
  697.         break;
  698.         }
  699.  
  700.         if (sending)
  701.         *s1++ = '\\';
  702.         *s1++ = cur_chr;
  703.         break;
  704.         }
  705.     }
  706.  
  707.     if (add_return)
  708.     *s1++ = '\r';
  709.  
  710.     *s1++ = '\0'; /* guarantee closure */
  711.     *s1++ = '\0'; /* terminate the string */
  712.     return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
  713.     }
  714.  
  715. /*
  716.  * Process the expect string
  717.  */
  718. void chat_expect(s)
  719. register char *s;
  720.     {
  721.     if (strcmp(s, "ABORT") == 0)
  722.     {
  723.     ++abort_next;
  724.     return;
  725.     }
  726.  
  727.     if (strcmp(s, "TIMEOUT") == 0)
  728.     {
  729.     ++timeout_next;
  730.     return;
  731.     }
  732.  
  733.     while (*s)
  734.     {
  735.     register char *hyphen;
  736.  
  737.     for (hyphen = s; *hyphen; ++hyphen)
  738.         if (*hyphen == '-')
  739.         if (hyphen == s || hyphen[-1] != '\\')
  740.             break;
  741.     
  742.     if (*hyphen == '-')
  743.         {
  744.         *hyphen = '\0';
  745.  
  746.         if (get_string(s))
  747.         return;
  748.         else
  749.         {
  750.         s = hyphen + 1;
  751.  
  752.         for (hyphen = s; *hyphen; ++hyphen)
  753.             if (*hyphen == '-')
  754.             if (hyphen == s || hyphen[-1] != '\\')
  755.                 break;
  756.  
  757.         if (*hyphen == '-')
  758.             {
  759.             *hyphen = '\0';
  760.  
  761.             chat_send(s);
  762.             s = hyphen + 1;
  763.             }
  764.         else
  765.             {
  766.             chat_send(s);
  767.             return;
  768.             }
  769.         }
  770.         }
  771.     else
  772.         if (get_string(s))
  773.         return;
  774.         else
  775.         {
  776.         if (fail_reason)
  777.             syslog(LOG_INFO, "Failed (%s)", fail_reason);
  778.         else
  779.             syslog(LOG_INFO, "Failed");
  780.  
  781.         unlock();
  782.         terminate(1);
  783.         }
  784.     }
  785.     }
  786.  
  787. char *character(c)
  788. char c;
  789.     {
  790.     static char string[10];
  791.     char *meta;
  792.  
  793.     meta = (c & 0x80) ? "M-" : "";
  794.     c &= 0x7F;
  795.  
  796.     if (c < 32)
  797.     sprintf(string, "%s^%c", meta, (int)c + '@');
  798.     else
  799.     if (c == 127)
  800.         sprintf(string, "%s^?", meta);
  801.     else
  802.         sprintf(string, "%s%c", meta, c);
  803.  
  804.     return (string);
  805.     }
  806.  
  807. /*
  808.  *  process the reply string
  809.  */
  810. void chat_send (s)
  811. register char *s;
  812.     {
  813.     if (abort_next)
  814.     {
  815.     char *s1;
  816.  
  817.     abort_next = 0;
  818.  
  819.     if (n_aborts >= MAX_ABORTS)
  820.         fatal("Too many ABORT strings");
  821.  
  822.     s1 = clean(s, 0);
  823.  
  824.     if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
  825.         {
  826.         syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s);
  827.         die();
  828.         }
  829.  
  830.     abort_string[n_aborts++] = s1;
  831.  
  832.     if (verbose)
  833.         {
  834.         logf("abort on (");
  835.  
  836.         for (s1 = s; *s1; ++s1)
  837.         logf(character(*s1));
  838.  
  839.         logf(")\n");
  840.         }
  841.     }
  842.     else
  843.     if (timeout_next)
  844.         {
  845.         timeout_next = 0;
  846.         timeout = atoi(s);
  847.  
  848.         if (timeout <= 0)
  849.         timeout = DEFAULT_CHAT_TIMEOUT;
  850.  
  851.         if (verbose)
  852.         {
  853.         syslog(LOG_INFO, "timeout set to %d seconds", timeout);
  854.         }
  855.         }
  856.     else
  857.         {
  858.         if (strcmp(s, "EOT") == 0)
  859.         s = "^D\\c";
  860.         else
  861.         if (strcmp(s, "BREAK") == 0)
  862.             s = "\\K\\c";
  863.         if ( ! put_string(s))
  864.         {
  865.         syslog(LOG_INFO, "Failed");
  866.         unlock();
  867.         terminate(1);
  868.         }
  869.         }
  870.     }
  871.  
  872. int get_char()
  873.     {
  874.     int status;
  875.     char c;
  876.  
  877.     status = read(0, &c, 1);
  878.  
  879.     switch (status)
  880.     {
  881.     case 1:
  882.         return ((int)c & 0x7F);
  883.  
  884.     default:
  885.         syslog(LOG_WARNING, "warning: read() on stdin returned %d",
  886.            status);
  887.  
  888.     case -1:
  889.         if ((status = fcntl(0, F_GETFL, 0)) == -1)
  890.         sysfatal("Can't get file mode flags on stdin");
  891.         else
  892.         if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1)
  893.             sysfatal("Can't set file mode flags on stdin");
  894.  
  895.         return (-1);
  896.     }
  897.     }
  898.  
  899. int put_char(c)
  900. char c;
  901.     {
  902.     int status;
  903.  
  904.     delay();
  905.  
  906.     status = write(1, &c, 1);
  907.  
  908.     switch (status)
  909.     {
  910.     case 1:
  911.         return (0);
  912.  
  913.     default:
  914.         syslog(LOG_WARNING, "warning: write() on stdout returned %d",
  915.            status);
  916.  
  917.     case -1:
  918.         if ((status = fcntl(0, F_GETFL, 0)) == -1)
  919.         sysfatal("Can't get file mode flags on stdin");
  920.         else
  921.         if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1)
  922.             sysfatal("Can't set file mode flags on stdin");
  923.  
  924.         return (-1);
  925.     }
  926.     }
  927.  
  928. int write_char (c)
  929. int c;
  930.     {
  931.     if (alarmed || put_char(c) < 0)
  932.     {
  933.     extern int errno;
  934.  
  935.     alarm(0); alarmed = 0;
  936.  
  937.     if (verbose)
  938.         {
  939.         if (errno == EINTR || errno == EWOULDBLOCK)
  940.         syslog(LOG_INFO, " -- write timed out");
  941.         else
  942.         syslog(LOG_INFO, " -- write failed: %m");
  943.         }
  944.     return (0);
  945.     }
  946.     return (1);
  947.     }
  948.  
  949. int put_string (s)
  950. register char *s;
  951.     {
  952.     s = clean(s, 1);
  953.  
  954.     if (verbose)
  955.     {
  956.     logf("send (");
  957.  
  958.     if (quiet)
  959.         logf("??????");
  960.     else
  961.         {
  962.         register char *s1 = s;
  963.  
  964.         for (s1 = s; *s1; ++s1)
  965.         logf(character(*s1));
  966.         }
  967.  
  968.     logf(")\n");
  969.     }
  970.  
  971.     alarm(timeout); alarmed = 0;
  972.  
  973.     while (*s)
  974.     {
  975.     register char c = *s++;
  976.  
  977.     if (c != '\\')
  978.         {
  979.         if (!write_char (c))
  980.         return 0;
  981.         continue;
  982.         }
  983.  
  984.     c = *s++;
  985.     switch (c)
  986.         {
  987.     case 'd':
  988.         sleep(1);
  989.         break;
  990.  
  991.     case 'K':
  992.         break_sequence();
  993.         break;
  994.  
  995.     case 'p':
  996.         usleep(10000); /* 1/100th of a second. */
  997.         break;
  998.  
  999.     default:
  1000.         if (!write_char (c))
  1001.         return 0;
  1002.         break;
  1003.         }
  1004.     }
  1005.  
  1006.     alarm(0);
  1007.     alarmed = 0;
  1008.     return (1);
  1009.     }
  1010.  
  1011. /*
  1012.  *    'Wait for' this string to appear on this file descriptor.
  1013.  */
  1014. int get_string(string)
  1015. register char *string;
  1016.     {
  1017.     char temp[STR_LEN];
  1018.     int c, printed = 0, len, minlen;
  1019.     register char *s = temp, *end = s + STR_LEN;
  1020.  
  1021.     fail_reason = (char *)0;
  1022.     string = clean(string, 0);
  1023.     len = strlen(string);
  1024.     minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
  1025.  
  1026.     if (verbose)
  1027.     {
  1028.     register char *s1;
  1029.  
  1030.     logf("expect (");
  1031.  
  1032.     for (s1 = string; *s1; ++s1)
  1033.         logf(character(*s1));
  1034.  
  1035.     logf(")\n");
  1036.     }
  1037.  
  1038.     if (len > STR_LEN)
  1039.     {
  1040.     syslog(LOG_INFO, "expect string is too long");
  1041.     return 0;
  1042.     }
  1043.  
  1044.     if (len == 0)
  1045.     {
  1046.     if (verbose)
  1047.         {
  1048.         syslog(LOG_INFO, "got it");
  1049.         }
  1050.  
  1051.     return (1);
  1052.     }
  1053.  
  1054.     alarm(timeout); alarmed = 0;
  1055.  
  1056.     while ( ! alarmed && (c = get_char()) >= 0)
  1057.     {
  1058.     int n, abort_len;
  1059.  
  1060.     if (verbose)
  1061.         {
  1062.         if (c == '\n')
  1063.         logf("\n");
  1064.         else
  1065.         logf(character(c));
  1066.         }
  1067.  
  1068.     *s++ = c;
  1069.  
  1070.     if (s - temp >= len &&
  1071.         c == string[len - 1] &&
  1072.         strncmp(s - len, string, len) == 0)
  1073.         {
  1074.         if (verbose)
  1075.         {
  1076.         logf(" -- got it\n");
  1077.         }
  1078.  
  1079.         alarm(0); alarmed = 0;
  1080.         return (1);
  1081.         }
  1082.  
  1083.     for (n = 0; n < n_aborts; ++n)
  1084.         if (s - temp >= (abort_len = strlen(abort_string[n])) &&
  1085.         strncmp(s - abort_len, abort_string[n], abort_len) == 0)
  1086.         {
  1087.         if (verbose)
  1088.             {
  1089.             logf(" -- failed\n");
  1090.             }
  1091.  
  1092.         alarm(0); alarmed = 0;
  1093.         strcpy(fail_reason = fail_buffer, abort_string[n]);
  1094.         return (0);
  1095.         }
  1096.  
  1097.     if (s >= end)
  1098.         {
  1099.         strncpy(temp, s - minlen, minlen);
  1100.         s = temp + minlen;
  1101.         }
  1102.  
  1103.     if (alarmed && verbose)
  1104.         syslog(LOG_WARNING, "warning: alarm synchronization problem");
  1105.     }
  1106.  
  1107.     alarm(0);
  1108.     
  1109.     if (verbose && printed)
  1110.     {
  1111.     if (alarmed)
  1112.         logf(" -- read timed out\n");
  1113.     else
  1114.         {
  1115.         logflush();
  1116.         syslog(LOG_INFO, " -- read failed: %m");
  1117.         }
  1118.     }
  1119.  
  1120.     alarmed = 0;
  1121.     return (0);
  1122.     }
  1123.  
  1124. #ifdef ultrix
  1125. #undef NO_USLEEP
  1126. #include <sys/types.h>
  1127. #include <sys/time.h>
  1128.  
  1129. /*
  1130.   usleep -- support routine for 4.2BSD system call emulations
  1131.   last edit:  29-Oct-1984     D A Gwyn
  1132.   */
  1133.  
  1134. extern int      select();
  1135.  
  1136. int
  1137. usleep( usec )                  /* returns 0 if ok, else -1 */
  1138.     long        usec;        /* delay in microseconds */
  1139. {
  1140.     static struct            /* `timeval' */
  1141.     {
  1142.         long    tv_sec;        /* seconds */
  1143.         long    tv_usec;    /* microsecs */
  1144.     }   delay;        /* _select() timeout */
  1145.  
  1146.     delay.tv_sec = usec / 1000000L;
  1147.     delay.tv_usec = usec % 1000000L;
  1148.  
  1149.     return select( 0, (long *)0, (long *)0, (long *)0, &delay );
  1150. }
  1151. #endif
  1152.  
  1153. /*
  1154.  *    Delay an amount appropriate for between typed characters.
  1155.  */
  1156. void delay()
  1157.     {
  1158. # ifdef NO_USLEEP
  1159.     register int i;
  1160.  
  1161.     for (i = 0; i < 30000; ++i)        /* ... did we just say appropriate? */
  1162.     ;
  1163. # else /* NO_USLEEP */
  1164.     usleep(100);
  1165. # endif /* NO_USLEEP */
  1166.     }
  1167.